﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Timers;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;
using SharedObjects;
using SharedObjects.Registration;
using TheGame.Server;
using TheGameLib;
using Timer = System.Timers.Timer;

namespace TheGame.Webservices
{
	public partial class TheGameService
	{
		private Timer _heartbeatTimer;

		public bool VerifySession(Guid sessionId)
		{
			if (World.Instance.GetAgentSession(sessionId) == null)
				return false;
			return true;
		}

		private void HeartbeatTimerElapsed(object sender, ElapsedEventArgs e)
		{
			try
			{
				if (Callback != null)
					Callback.Heartbeat(World.Instance.WorldTime);
			}
			catch
			{
				/* This can coincide with a previous serverdisconnect, thus it will fail. ignore the resulting exception. */
			}
		}

		private void SendServerError(ServerErrorSeverity severity, string message, params object[] parameters)
		{
			StackTrace trace = new StackTrace();
#if DEBUG
			string callerName = trace.GetFrame(1).GetMethod().Name;
#else
			string callerName = "";
#endif
			message = string.Format(message, parameters);
			if(Callback != null)
				Callback.ServerError(severity, string.Format("({0}) {1}", callerName, message));
		}

		#region Trace handling
		void ConnectionTraceUpdated(object sender, TraceEventArgs e)
		{
			if (!(sender is AgentConnection))
				return;
			
			AgentConnection conn = sender as AgentConnection;
			if (Callback != null)
				Callback.Trace(conn.ConnectionId, e.RemainingMilliseconds, null);
		}
		void ConnectionTraceEnded(object sender, TraceEndedEventArgs e)
		{
			if (Callback != null)
				Callback.TraceEnded(e.ConnectionId, e.TraceTimeElapsed);
			if (e.TraceTimeElapsed)
			{
				//CreateAndAssignGateway()
				//assign old gateway to a new Confiscation object
				//assign new gateway to agent
			}
		} 
		#endregion

		#region Login/Logout
		public ClientConfiguration Login(string login, string password)
		{
			Account account = (from Account a in Db where a.Login == login && a.Password == password select a).FirstOrDefault();
			if(account == null)
			{
				SendServerError(ServerErrorSeverity.Error, "User account with that login/password combination was not found.");
				return null;
			}
			if(account.AccountStatus != AccountStatus.Active)
			{
				string message = "User account is inactive.\nReason: {0}";
				string reason = "";
				switch (account.AccountStatus)
				{
					case AccountStatus.Incomplete:
						reason = "Incomplete account";
						break;
					case AccountStatus.TempBanned:
						reason = "Account is temporarily banned.\nPlease contact support via email accountmanagement@TheGameDomain.";
						break;
					case AccountStatus.PermBanned:
						reason = "Account is permanently banned.\nAll paypal subscriptions have been suspended.";
						break;
					case AccountStatus.Unpaid:
						reason = "Account is not paid. To reactivate the account, please contact support via email billing@TheGameDomain.";
						break;
				}
				SendServerError(ServerErrorSeverity.Error, string.Format(message, reason));
				return null;
			}
			Agent agent = account.Agent;
			if (!account.IsAdmin)
			{
				RegisteredUser registeredUser = (from RegisteredUser ru in Db where ru.Email == login && ru.UserGameAccount != null && ru.UserGameAccount.Password == password && ru.UserGameAccount.AccountStatus == AccountStatus.Active select ru).FirstOrDefault();
				//check payment status for this account
				if(registeredUser == null)
				{
					SendServerError(ServerErrorSeverity.Error, "Error fetching registered user data. Login attempt is logged, UserAccount has been set to temporary ban. You will not be able to login until we have investigated the issue.");
					return null;
				}
#if USE_PAYPAL
				if (DateTime.Now - registeredUser.LastCheckDate > TimeSpan.FromDays(30))
				{
					PaypalController ctrl = new PaypalController();
					if (!ctrl.IsSubscriptionValid(registeredUser.PaypalProfileId))
					{
						SendServerError(ServerErrorSeverity.Fatal, "Subscription invalid. Access denied. Please check your paypal subscription for this game.");
						registeredUser.UserGameAccount.AccountStatus = AccountStatus.Unpaid;
						db.PersistEntity(registeredUser.UserGameAccount);
						db.Commit();
						return null;
					}
					registeredUser.LastCheckDate = DateTime.Now;
					db.PersistEntity(registeredUser);
					db.Commit();
				}
#endif
			}
			
			if(agent != null) //account exists and is marked active
			{
				if(!World.Instance.IsAgentOnline(agent.Id))
				{
					AgentSessionObject aso = new AgentSessionObject(agent);
					World.Instance.AddAgentSession(aso);
					NetworkAddress myPublicGatewayAddress = (from ComputerSystem cs in Db where cs.Corporation.Id == agent.Corporation.Id && cs.IsGatewayCentral select cs.NetworkAddress).FirstOrDefault();
					string ip = agent.Gateway.ComputerSystem.NetworkAddress.ToString();

					if (myPublicGatewayAddress != null)
						ip += string.Format(" (Gateway Address: {0})", myPublicGatewayAddress);

					ClientConfiguration config = new ClientConfiguration
					{
						SessionId = aso.SessionId,
						CorporationId = agent.Corporation.Id,
						GatewayId = agent.Gateway.Id,
						SystemId = agent.Gateway.ComputerSystem.Id,
						RootDirectoryId = agent.Gateway.ComputerSystem.RootDirectory.Id,
						MyKnownComputers = GetMyKnownComputerSystems(aso.SessionId),
						Ip = ip
					};
					aso.SessionDisconnect += SessionDisconnect;
					aso.NewMail += SessionNewMail;
					aso.NewBankTransaction += SessionBankTransaction;
					World.Instance.GlobalChatMessageReceived += InstanceGlobalChatMessageReceived;
					_heartbeatTimer = new Timer(1000);
					_heartbeatTimer.Elapsed += HeartbeatTimerElapsed;
					_heartbeatTimer.Start();
					//start the queued mail notifications in separate thread.
					new Thread(new ThreadStart(delegate
					{
						Thread.Sleep(3000);
						if (Db != null)
						{
							var notifications = (from QueuedMailNotification cmn in Db where cmn.AgentId == agent.Id select cmn);
							var banknotifications = (from QueuedTransactionNotification qtn in Db where qtn.AgentId == agent.Id select qtn);
							foreach (QueuedMailNotification n in notifications)
							{
								SessionNewMail(null, new MailNotifyEventArgs {ReceivingServerName = n.Target, SourceEmailAddress = n.Sender});
								Db.Delete(n);
								Thread.Sleep(500);
							}
							foreach (QueuedTransactionNotification qtn in banknotifications)
							{
								SessionBankTransaction(null,
								                       new BankTransactionNotifyEventArgs
								                       {Amount = qtn.TransactionAmount, ReceivingAccount = qtn.DestinationAccountInfo, SendingAccount = qtn.SourceAccountInfo, TransactionDate = qtn.TransactionDate});
								Db.Delete(qtn);
								Thread.Sleep(500);
							}
							Db.Commit();
						}
					})).Start();
					return config;
				}
				SendServerError(ServerErrorSeverity.Error, "Agent already logged in. Please wait at least 5 minutes and try again.");
				return null;
			}
			SendServerError(ServerErrorSeverity.Error, "Login failed. Incorrect email/password combination.");
			return null;
		}

		void SessionBankTransaction(object sender, BankTransactionNotifyEventArgs e)
		{
			if(Callback != null)
				Callback.BankTransaction(e.Amount, e.SendingAccount, e.ReceivingAccount, e.TransactionDate);
		}

		void SessionNewMail(object sender, MailNotifyEventArgs e)
		{
			if(Callback != null)
				Callback.Email(e.SourceEmailAddress, e.ReceivingServerName);
		}

		/// <summary>
		/// This gets fired upon idletimeout.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void SessionDisconnect(object sender, EventArgs e)
		{
			if (sender is AgentSessionObject)
			{
				((AgentSessionObject) sender).Dispose();
			}

			if(Callback != null)
				Callback.ServerDisconnect();
			Callback = null;
		}

		public bool Logout(Guid sessionId, string login, string password)
		{
			if (!CheckIsValidAgent(sessionId))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return false;
			}
			AgentSessionObject aso = World.Instance.GetAgentSession(sessionId);
			if (aso != null)
			{
				lock (aso)
				{
					var loginCheck = (from Account a in Db where a.Login == login && a.Password == password && a.AccountStatus == AccountStatus.Active && a.Agent.Id == aso.AgentInDb.Id select a.Agent);
					if (loginCheck.Count() == 1)
					{
						World.Instance.RemoveAgentSession(sessionId);
						Callback = null;
						_heartbeatTimer.Stop();
						return true;
					}
				}
			}
			SendServerError(ServerErrorSeverity.Warning, "Could not find session object or agent.");
			return false;
		}
		#endregion

		#region File Operations
		public List<SystemFile> GetFilesInDirectory(Guid sessionId, ulong directoryId)
		{
			if (!CheckIsValidAgent(sessionId))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return null;
			}
			AgentSessionObject aso = World.Instance.GetAgentSession(sessionId);
			if (aso == null)
			{
				SendServerError(ServerErrorSeverity.Error, "Session object null.");
				return null;
			}

			ulong systemId = (from ComputerSystem cs in Db where cs.RootDirectory.Id == directoryId select cs.Id).FirstOrDefault();
			if (systemId == 0)
			{
				SendServerError(ServerErrorSeverity.Error, "No system found for specified directory.");
				return null;
			}
			if(aso.AgentInDb.Gateway.ComputerSystem.Id != systemId) //system not local system
			{
				if ((from x in aso.AgentInDb.ComputerSystemIds where x == systemId select x).Count() != 1) //system not known to agent, cannot be connected
				{
					SendServerError(ServerErrorSeverity.Error, "Directory does not belong to known computer system.");
					return null;
				}
			}
			List<SystemFile> files = (from SystemFile f in Db where f.ParentId == directoryId && !f.IsDeleted select f).ToList();
			return files;
		}

		public List<SystemFile> GetSystemRoot(Guid agentId, ulong systemId)
		{
			Agent me;
			if (!CheckIsValidAgent(agentId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return null;
			}
			
			//check if agent is connected to system
			if(me.Gateway.ComputerSystem.Id != systemId) // not our own system, require connectionId
			{
				//we're not connected to this system either
				AgentSessionObject aso = World.Instance.GetAgentSession(agentId);
				AgentConnection conn;
				lock (aso)
				{
					conn = aso.GetAgentConnectionByTargetSystem(systemId);
				}
				if (conn == null) //no connection to this system for this agent exists
				{
					SendServerError(ServerErrorSeverity.Error, "Cannot access system without connecting to it.");
					return null;
				}

			}
			//var parent = (from SystemDirectory d in db from SystemFile f in d.Files where f.ID == sourceFileId select d).FirstOrDefault();
			SystemDirectory dir = (from ComputerSystem cs in Db where cs.Id == systemId select cs.RootDirectory).FirstOrDefault();
			if (dir == null)
			{
				SendServerError(ServerErrorSeverity.Error, "System does not have a valid root directory.");
				return null;
			}
			var files = (from SystemFile f in Db where f.ParentId == dir.Id orderby f.Name ascending select f);
			//dir.Files = dir.Files.Where(it => !it.IsDeleted).OrderBy(it => it.Name).ToList();
			return files.ToList();
		}
		#endregion

		#region Gateway Handling
		public int GetMyTotalMemory(Guid sessionId)
		{
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return -1;
			}

			return me.Gateway.GetTotalMemory();
		}

		public double GetMyTotalCpuSpeed(Guid sessionId)
		{
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return -1;
			}
			return me.Gateway.GetTotalCpuSpeed();
		}

		public double GetMyTotalBandwidth(Guid sessionId)
		{
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return -1;
			}
			return me.Gateway.GetTotalBandwidth();
		}

		public double GetProgramSpeed(Guid sessionId, ulong programId)
		{
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return -1;
			}

			Program program = (from Program p in Db where p.Id == programId select p).FirstOrDefault();
			if (program == null)
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid program was specified.");
				throw new ArgumentException("programId");
			}

			// A program's speed is determined by the global default speed (GDS) for programs, which is 1.0 for simplicity.
			// The default speed is influenced by the programs SpeedModifier (SPM) and the Gateway's hardware, which is specified in
			// Program::SpeedType.
			// General rule: The higher the speed of a hardware component, the lower the resulting execution time.
			// The lowest possible CPU runs at 1GHz, and does not decrease the execution time.
			// A machine with 1 basic cpu runs every program with it's default speed (SPM seconds).
			// A machine with 10 basic cpus runs every program with 1/10th of the program's CPU speed
			// Example: ExecutionTime = SPM / HardwareSpeed = 4.5s / 3.45 CPU speed
			switch (program.SpeedType)
			{
				case SpeedType.Cpu:
					return program.SpeedModifier/me.Gateway.GetTotalCpuSpeed();
				case SpeedType.Bandwidth:
					return program.SpeedModifier/me.Gateway.GetTotalBandwidth();
			}
			SendServerError(ServerErrorSeverity.Error, "Specified program does not have a speed type.");
			return -1.0;
		}

		public bool CreateAndAssignGateway(Guid agentId, Gateway newGateway)
		{
			SendServerError(ServerErrorSeverity.Error, "Obsolete method was called.");
			return false;
/*
			Agent me;
			if(CheckIsValidAgent(agentId, out me, true))
			{
				Gateway oldGateway = me.Gateway;
				newGateway.ComputerSystem = oldGateway.ComputerSystem; // all files etc on gateway will be transfered
				me.Gateway = newGateway;
				db.PersistEntity(me);
				db.DeleteEntity(oldGateway);
				db.Commit();
			}
			return false;
*/
		}
		#endregion

		#region Program handling
		/// <summary>
		/// 
		/// </summary>
		/// <param name="sessionId"></param>
		/// <param name="programId"></param>
		/// <param name="parameters">If bypasser: [0]: SystemId, [1]: SecSysId, [2]: ConnectionId, [3]: Optional parameters</param>
		/// <returns></returns>

		public bool ExecuteProgram(Guid sessionId, ulong programId, object[] parameters)
		{
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return false;
			}

			Program prog = (from Program p in Db where p.Id == programId select p).FirstOrDefault();
			if(prog == null)
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid program specified.");
				return false;
			}
			//check if agent actually owns program
			var installedPrograms = (from ProgramFile x in Db where x.ParentId == me.Gateway.ComputerSystem.RootDirectory.Id && x.Program.Id == programId select x);
			var defaultPrograms = (from Program p in Db where p.IsDefault && p.Id == programId select p);
			if (installedPrograms.Count() == 0 && defaultPrograms.Count() == 0)
			{
				SendServerError(ServerErrorSeverity.Error, "Cannot execute program that is not in your possession.");
				return false;
			}

			IObjectContainer localDb = Db;

			#region if is bypasser
			if (prog is Bypasser)
			{
				//in this case parameters must contain at least 2 values.
				//Value 0 = SystemId,
				//Value 1 = SecSysID. 
				//Value 2 = ConnectionID
				//Value 3 = optional Username, to specify a specific account to be used when bypassing.
				if (parameters.Count() < 3)
				{
					SendServerError(ServerErrorSeverity.Error, "Invalid parameter count for bypasser.");
					return false;
				}
				if (!(parameters[0] is ulong))
				{
					SendServerError(ServerErrorSeverity.Error, "System Identifier not in parameters list!");
					return false;
				}
				if (!(parameters[1] is ulong))
				{
					SendServerError(ServerErrorSeverity.Error, "Security System identifier not in parameters list!");
					return false;
				}
				if (!(parameters[2] is Guid))
				{
					SendServerError(ServerErrorSeverity.Error, "Connection identifier not in parameters list!");
					return false;
				}

				ulong systemId = (ulong)parameters[0];
				ulong secSysId = (ulong)parameters[1];
				Guid connectionId = (Guid)parameters[2];

				AgentSessionObject aso = World.Instance.GetAgentSession(sessionId);
				if (aso == null)
				{
					SendServerError(ServerErrorSeverity.Error, "Session object not found for session.");
					return false;
				}
				AgentConnection conn;
				lock (aso)
				{
					conn = aso.GetAgentConnection(connectionId);
				}
				if (conn == null)
				{
					SendServerError(ServerErrorSeverity.Error, "No connection was registered to specified target system.");
					return false;
				} 
				
				ComputerSystem cs = (from ComputerSystem c in Db where c.Id == systemId select c).FirstOrDefault();
				if (cs == null || cs.SecuritySystem == null || cs.SecuritySystem.Count == 0)
				{
					SendServerError(ServerErrorSeverity.Error, "Target system does not exist or has no security systems.");
					return false;
				}

				SecuritySystem secSys = (from ss in cs.SecuritySystem where ss.Id == secSysId select ss).FirstOrDefault();
				if (secSys == null)
				{
					SendServerError(ServerErrorSeverity.Error, "Specified security system does not exist.");
					return false;
				}

				Bypasser bp = prog as Bypasser;
				ComputerSystemAccount account = new ProgramExecutor(sessionId).Execute(ref localDb, bp, parameters);
				if (account == null) //bypass failed (either incompatible bypasser, no default-account found on system or wrong username specified)
				{
					//SendServerError(ServerErrorSeverity.Error, "Bypass failed. Incompatible bypasser used, no default-account exists on target system, or wrong username specified.");
					//conn.Trace();
					return false;
				}
				//if we get here, the bypass was indeed successful, lets see if for the right user account.
				lock(conn)
				{
					if (conn.ComputerSystemAccountId == 0)
						conn.ComputerSystemAccountId = account.Id;
					else if (conn.ComputerSystemAccountId != account.Id)
					{
						SendServerError(ServerErrorSeverity.Error, "The system account being used for this bypass must always be the same. You cannot bypass Security systems with different system accounts. The first bypass defines which system account must be used.");
						return false;
					}

					conn.SetBypassSuccessful(secSysId);
				}
				return true;
			}
			#endregion
			//parameter layout for programs is always ProgramMethod specific.
			//The validation of any connectionIds will *only* be done inside ProgramExecutor, and specific to each method.
			//todo: PX should always throw exceptions, which we will then transform into SSE's here. (SSE = send server error)
			ProgramExecutor px = new ProgramExecutor(sessionId);
			return px.Execute(ref localDb, prog, parameters);
		}

		public List<Program> GetMyPrograms(Guid sessionId)
		{
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return null;
			}
			List<Program> programs = new List<Program>();
			
			//Programs marked as "Default" (ie. integral part of gateway OS)
			programs.AddRange((from Program p in Db where p.IsDefault && !p.IsAdminOnly select p).ToList());

			//programs installed on the agent's cs
			//var programFiles = (from ProgramFile x in db where x.ParentId == me.Gateway.ComputerSystem.RootDirectory.Id && !x.IsDeleted select x).ToList();
			programs.AddRange((from ProgramFile x in Db where x.ParentId == me.Gateway.ComputerSystem.RootDirectory.Id && !x.IsDeleted select x.Program));

			bool admin = (from Account a in Db where a.Agent == me select a.IsAdmin).FirstOrDefault();
			if(admin)
				programs.AddRange((from Program p in Db where p.IsAdminOnly select p).ToList());

			return programs;
		}
		#endregion

		#region ComputerSystem handling
		public List<SmallComputerSystem> GetMyKnownComputerSystems(Guid sessionId)
		{
			Agent me;
			if (CheckIsValidAgent(sessionId, out me, true))
			{
				//if we're admin, we're always seeing all systems (except invisible user gateways));)
				return (from ComputerSystem cs in Db
						where cs.AlwaysInvisible == false
						select (SmallComputerSystem)cs).ToList();
				//select new SmallComputerSystem
				//{
				//    Corporation = cs.Corporation,
				//    ID = cs.ID,
				//    IsDeleted = cs.IsDeleted,
				//    MapX = cs.MapX,
				//    MapY = cs.MapY,
				//    Name = cs.Name,
				//    IsGatewayCentral = cs.IsGatewayCentral,
				//    AlwaysInvisible = cs.AlwaysInvisible
				//}).ToList();
			}
			if (CheckIsValidAgent(sessionId, out me))
			{
				//if we're peon, we can only see systems that are known to us
				//var list = (from ulong csId in me.ComputerSystems from ComputerSystem c in db where c.ID == csId select c);
				var retval = (from ComputerSystem cs in Db from ulong x in me.ComputerSystemIds where cs.Id == x select (SmallComputerSystem)cs).ToList();
				return retval;
			}
			SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
			return null;
		}

		public List<ReadableComputerSystemLog> GetSystemLogs(Guid sessionId, ulong systemId)
		{
			if (!CheckIsValidAgent(sessionId))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return null;
			}
			AgentSessionObject aso = World.Instance.GetAgentSession(sessionId);
			AgentConnection conn;
			lock(aso)
			{
				conn = aso.GetAgentConnectionByTargetSystem(systemId);
			}
			if (conn == null)
			{
				SendServerError(ServerErrorSeverity.Error, "No connection exists to target system.");
				return null;
			}

			var logs = (from ComputerSystemLog l in Db where l.LoggingComputerSystemId == systemId select (ReadableComputerSystemLog)l).ToList();//orderby l.TimeStamp descending 

			return logs.OrderByDescending(it => it.TimeStamp).ToList();
		}

		public bool CreateSystemAccount(Guid sessionId, ulong systemId, ComputerSystemAccount account)
		{
			SendServerError(ServerErrorSeverity.Fatal, "Method not yet complete.");
			return false;
#pragma warning disable 162
			Agent me;
			if (!CheckIsValidAgent(sessionId, out me))
			{
				SendServerError(ServerErrorSeverity.Error, "Invalid session id.");
				return false;
			}
			AgentSessionObject aso = World.Instance.GetAgentSession(sessionId);
			if (aso == null)
			{
				SendServerError(ServerErrorSeverity.Fatal, "No session object for session id.");
				return false;
			}
			AgentConnection conn = aso.GetAgentConnectionByTargetSystem(systemId);
			if (conn == null)
			{
				SendServerError(ServerErrorSeverity.Error, "No connection exists to target system.");
				return false;
			}
			ComputerSystem system = (from ComputerSystem cs in Db where cs.Id == systemId select cs).FirstOrDefault();
			if (system == null)
			{
				SendServerError(ServerErrorSeverity.Error, "Target system not found.");
				return false;
			}

			//check, that all credential types match the system's security systems.
			ComputerSystemAccount acct = new ComputerSystemAccount {Id = Guid.NewGuid().ToLong(), CreationTime = World.Instance.GetWorldTime(), IsTemporary = true, Username = account.Username};

			foreach(SecuritySystem secSys in system.SecuritySystem)
			{
				switch(secSys.CredentialType)
				{
					case CredentialType.UsernamePassword:
						if (account.Credentials.OfType<UsernamePasswordCredential>().Count() == 1)
						{
							UsernamePasswordCredential upc = account.Credentials.OfType<UsernamePasswordCredential>().First();
							if(!string.IsNullOrEmpty(upc.Username) && !string.IsNullOrEmpty(upc.Password))
							{
								upc.Id = Guid.NewGuid().ToLong();
								acct.Credentials.Add(upc);
							}
						}
						else
						{
							SendServerError(ServerErrorSeverity.Warning, "Account does not include username/password credential, but target system requires it.");
							return false;
						}
						break;
					case CredentialType.Fingerprint:
						if (account.Credentials.OfType<FingerprintCredential>().Count() == 1)
						{
							FingerprintCredential fc = account.Credentials.OfType<FingerprintCredential>().First();
							//check that credential file is attached
						}
						else
						{
							SendServerError(ServerErrorSeverity.Warning, "Account does not include fingerprint credential, but target system requires it.");
							return false;
						}
						break;
					case CredentialType.Retinal:
						if (account.Credentials.OfType<RetinalScanCredential>().Count() == 1)
						{
							RetinalScanCredential rsc = account.Credentials.OfType<RetinalScanCredential>().First();
							//check that credential file is attached
						}
						else
						{
							SendServerError(ServerErrorSeverity.Warning, "Account does not include retinal scan credential, but target system requires it.");
							return false;
						}
						break;
					case CredentialType.Dna:
						if (account.Credentials.OfType<DnaCredential>().Count() == 1)
						{
							DnaCredential dc = account.Credentials.OfType<DnaCredential>().First();
							//check that credential file is attached)
							continue;
						}
						else
						{
							SendServerError(ServerErrorSeverity.Warning, "Account does not include DNA credential, but target system requires it.");
							return false;
						}
				}
			}
			//at this point the newly created account object should be complete. So we persist it and are finished.
			system.Accounts.Add(acct);
			Db.PersistEntity(system);
			Db.Commit();
			return true;
#pragma warning restore 162
		}
		#endregion
	}
}
